package com.mbinno.android.comm.utils;

import android.content.Context;
import android.security.KeyPairGeneratorSpec;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;

import androidx.annotation.NonNull;

import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Calendar;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.security.auth.x500.X500Principal;

public class KeyStoreHelper {

    private static final String RSA_MODE_OAEP_DEF = "RSA/ECB/PKCS1Padding";

    private static final String ANDROID_KEYSTORE = "AndroidKeyStore";


    public static boolean isKeyPairGenerated(String keyAlias) throws Exception {
        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
        keyStore.load(null);
        return keyStore.containsAlias(keyAlias);
    }

    public static void generateKeyPair(Context context, String keyAlias) {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
                    "RSA", ANDROID_KEYSTORE);

            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(
                        keyAlias,
                        KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                        .setKeySize(2048)
                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                        .setDigests(KeyProperties.DIGEST_SHA256)
                        .build();

                keyPairGenerator.initialize(keyGenParameterSpec);
            } else {
                Calendar start = Calendar.getInstance();
                Calendar end = Calendar.getInstance();
                end.add(Calendar.YEAR, 30);

                KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
                        .setAlias(keyAlias)
                        .setSubject(new X500Principal("CN=MyKey, O=MyOrganization"))
                        .setSerialNumber(BigInteger.ONE)
                        .setStartDate(start.getTime())
                        .setEndDate(end.getTime())
                        .build();

                keyPairGenerator.initialize(spec);
            }

            keyPairGenerator.generateKeyPair();
        } catch (NoSuchAlgorithmException | NoSuchProviderException |
                 InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
    }


    public static byte[] encryptData(String keyAlias, String data) throws Exception {
        return encryptData(keyAlias, data.getBytes());
    }

    // 加密方法
    public static byte[] encryptData(String keyAlias, byte[] data) throws Exception {
        try {
            KeyStore keyStore = getKeyStore();

            PublicKey publicKey = keyStore.getCertificate(keyAlias).getPublicKey();

            Cipher cipher = Cipher.getInstance(RSA_MODE_OAEP_DEF);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            return cipher.doFinal(data);
        } catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException |
                 NoSuchPaddingException | IllegalBlockSizeException |
                 BadPaddingException | InvalidKeyException e) {
            throw new KeyStoreException(e);
        }
    }

    @NonNull
    private static KeyStore getKeyStore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
        keyStore.load(null);
        return keyStore;
    }

    // 解密方法
    public static byte[] decryptData(String keyAlias, String encryptedData) throws KeyStoreException {
        return decryptData(keyAlias, encryptedData.getBytes());
    }

    // 解密方法
    public static byte[] decryptData(String keyAlias, byte[] encryptedData) throws KeyStoreException {
        try {
            KeyStore keyStore = getKeyStore();
            PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, null);
            Cipher cipher = Cipher.getInstance(RSA_MODE_OAEP_DEF);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return cipher.doFinal(encryptedData);
        } catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException |
                 UnrecoverableKeyException | NoSuchPaddingException | IllegalBlockSizeException |
                 BadPaddingException | InvalidKeyException e) {
            throw new KeyStoreException(e);
        }

    }


}
